package com.jz.netthings.netty.server;

import com.jz.netthings.netty.decode.NettyChairDecoder;
import com.jz.netthings.netty.decode.NettyZxdcDecoder;
import com.jz.netthings.netty.decode.NettyZxdcLogDecoder;
import com.jz.netthings.netty.decode.NettyZxdcNewDecoder;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.serialization.ClassResolvers;
import io.netty.handler.codec.serialization.ObjectDecoder;
import io.netty.handler.codec.serialization.ObjectEncoder;
import io.netty.handler.timeout.IdleStateHandler;
import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.GenericFutureListener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.net.InetSocketAddress;
import java.util.concurrent.TimeUnit;

@Service("nettyServer")
public class NettyServer {

    Logger logger = LoggerFactory.getLogger(getClass());

    // 服务器端口
    @Value("${netty.zxdc.port}")
    private int zxdcPort;
    @Value("${netty.chair.port}")
    private int chairPort;
    @Value("${netty.client.port}")
    private int clientPort;
    @Value("${netty.log.port}")
    private int logPort;
    /**
     * 通过nio方式来接收连接和处理连接
     */
    private static EventLoopGroup boss_client = new NioEventLoopGroup(10);
    private static EventLoopGroup work_client = new NioEventLoopGroup(20);
    /**
     * 启动引导器
     */
    private static ServerBootstrap b_client = new ServerBootstrap();
    /**
     * 通过nio方式来接收连接和处理连接
     */
    private static EventLoopGroup boss_zxdc = new NioEventLoopGroup(40);
    private static EventLoopGroup work_zxdc = new NioEventLoopGroup(80);
    /**
     * 启动引导器
     */
    private static ServerBootstrap b_zxdc = new ServerBootstrap();

    /**
     * 通过nio方式来接收连接和处理连接
     */
    private static EventLoopGroup boss_log = new NioEventLoopGroup(10);
    private static EventLoopGroup work_log = new NioEventLoopGroup(20);
    /**
     * 启动引导器
     */
    private static ServerBootstrap b_log = new ServerBootstrap();
    /**
     * 通过nio方式来接收连接和处理连接
     */
    private static EventLoopGroup boss_chair = new NioEventLoopGroup(40);
    private static EventLoopGroup work_chair = new NioEventLoopGroup(80);
    /**
     * 启动引导器
     */
    private static ServerBootstrap b_chair = new ServerBootstrap();

    @Autowired
    private NettyServerHandler nettyServerHandler;
    @Autowired
    private NettyZxdcServerHandler nettyZxdcServerHandler;
    @Autowired
    private NettyLogServerHandler nettyLogServerHandler;
    @Autowired
    private NettyChairServerHandler nettyChairServerHandler;
    @Autowired
    private NettyZxdcOutBoundHandler nettyZxdcOutBoundHandler;


    public void run() {
        this.loadServer(boss_client, work_client, b_client, clientPort, 1);
        this.loadServer(boss_zxdc, work_zxdc, b_zxdc, zxdcPort, 2);
        this.loadServer(boss_log, work_log, b_log, logPort, 3);
        this.loadServer(boss_chair, work_chair, b_chair, chairPort, 4);
    }

    /**
     * 构造NettyServer
     *
     * @param boss
     * @param work
     * @param b
     * @param port
     * @param type ：1 表示对应到客户端，2 表示对应到单采机端
     */
    private void loadServer(EventLoopGroup boss, EventLoopGroup work, ServerBootstrap b, Integer port, Integer type) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    System.out.println("设置系统参数： System.setProperty(\"org.jboss.netty.epollBugWorkaround\", \"true\");");
                    System.setProperty("org.jboss.netty.epollBugWorkaround", "true");
                    b.group(boss, work)
                            // 设置nio类型的channel
                            .channel(NioServerSocketChannel.class)
                            // 设置监听端口
                            .localAddress(new InetSocketAddress(port))
                            .option(ChannelOption.CONNECT_TIMEOUT_MILLIS,10000)
                            .option(ChannelOption.SO_BACKLOG, 1048576 * 200)    //设置TCP缓冲区
                            .option(ChannelOption.SO_RCVBUF, 1048576 * 200)
                            .childOption(ChannelOption.SO_KEEPALIVE, Boolean.TRUE)    // 设置保持连接
                            .childOption(ChannelOption.SO_SNDBUF, 1048576 * 200)// 设置发送数据的缓存大小

                            // 设置通道初始化
                            .childHandler(new ChannelInitializer<SocketChannel>() {
                                //有连接到达时会创建一个channel
                                protected void initChannel(SocketChannel ch) throws Exception {

                                    if (type == 1) {
                                        // pipeline管理channel中的Handler
                                        // 在channel队列中添加一个handler来处理业务
//                    ch.pipeline().addLast(new LengthFieldBasedFrameDecoder(Integer.MAX_VALUE, 7, 4,0,11));
                                        ch.pipeline().addLast(new IdleStateHandler(10, 0, 0, TimeUnit.SECONDS));


                                        ch.pipeline().addLast(new ObjectEncoder());
                                        //添加对象解码器 负责对序列化POJO对象进行解码 设置对象序列化最大长度
                                        //设置线程安全的WeakReferenceMap对类加载器进行缓存 支持多线程并发访问  防止内存溢出
                                        ch.pipeline().addLast(new ObjectDecoder(Integer.MAX_VALUE,
                                                ClassResolvers.weakCachingConcurrentResolver(this.getClass().getClassLoader())
                                                /*ClassResolvers.cacheDisabled(null)*/));
                                        ch.pipeline().addLast(nettyServerHandler);

                                    } else if (type == 2) {
                                        ch.pipeline().addLast(new IdleStateHandler(10, 0, 0, TimeUnit.SECONDS));
                                        ch.pipeline().addLast(new NettyZxdcDecoder());
//                                        ch.pipeline().addLast(new NettyZxdcNewDecoder(29,8));
//                                        ch.pipeline().addLast(nettyZxdcOutBoundHandler);
                                        ch.pipeline().addLast(nettyZxdcServerHandler);
                                    } else if (type == 3) {
                                        ch.pipeline().addLast(new IdleStateHandler(10, 0, 0, TimeUnit.SECONDS));
                                        ch.pipeline().addLast(new NettyZxdcLogDecoder());
                                        ch.pipeline().addLast(nettyLogServerHandler);
                                    }else if (type == 4) {
                                        ch.pipeline().addLast(new IdleStateHandler(10, 0, 0, TimeUnit.SECONDS));
                                        ch.pipeline().addLast(new NettyChairDecoder());
//                                        ch.pipeline().addLast(new NettyZxdcNewDecoder(39,8));
                                        ch.pipeline().addLast(nettyChairServerHandler);
                                    }


                                }
                            });
                    // 配置完成，开始绑定server
                    // 通过调用sync同步方法阻塞直到绑定成功 ​
                    logger.info("Netty 服务启动，绑定端口【" + port + "】...");
//                    ChannelFuture f = b.bind().sync();
//                    // 监听服务器关闭事件 // 应用程序会一直等待，直到channel关闭
//                    f.channel().closeFuture().sync();

                    ChannelFuture f = b.bind();
                    f.awaitUninterruptibly();

                    if (f.isCancelled()) {
                        System.out.println("取消连接尝试....");
                    } else if (!f.isSuccess()) {
                        f.cause().printStackTrace();
                    } else {
                        System.out.println("成功建立连接...");
                        ChannelFuture future = f.channel().closeFuture();
                        future.awaitUninterruptibly();

                        System.out.println("-----future.isSuccess()---------"+future.isSuccess());
                        System.out.println("-----future.isDone()---------"+future.isDone());
                        System.out.println("-----future.isCancelled()---------"+future.isCancelled());
                        System.out.println("-----future.isCancellable()---------"+future.isCancellable());
                        // Connection established successfully
                    }

//                    f.addListener(new GenericFutureListener() {
//                        @Override
//                        public void operationComplete(Future future) throws Exception {
//                            if (future.isSuccess()){
//                                f.channel().closeFuture();
//                            }else if (future.isDone()){
//
//                            }
//                        }
//                    });


                } catch (Exception e) {
                    logger.error("Netty 服务启动失败！", e);
                } finally {
                    // 关闭EventLoopGroup，释放掉所有资源包括创建的线程
                    logger.info("关闭EventLoopGroup，释放掉所有资源包括创建的线程...");
                    work.shutdownGracefully();
                    boss.shutdownGracefully();
                }
            }
        }).start();
    }


}
